(ns samber.services.user.password
  (:require
    [toucan.db :as db]
    [honeysql.core :as hsql]
    [samber.db.models :as models]
    [java-time :as time]
    [clojure.tools.logging :as log]
    [samber.config :refer [env]]
    [promesa.exec :as exec]
    [cuerdas.core :as str]
    [samber.middleware.exception :as exception]
    [buddy.hashers :as hashers]
    [buddy.core.hash :as hash]
    [buddy.core.codecs :as codecs]
    [samber.services.http-request :as http-service]))

(defn change-password [token params]
  ;; check confirmation
  (if-not (= (:password params) (:password-confirmation params))
    (throw (ex-info "check" {:type ::exception/check :msg "confirmation not match!"})))

  ;; check current password
  (let [entity (db/select-one models/User (:id token))]
    (if-not (hashers/check (:current-password params) (:encrypted_password entity))
      (throw (ex-info "check" {:type ::exception/check :msg "password not match!"}))))

  ;; update db
  (db/update! models/User (:id token) {:password      (hashers/derive (:password params))
                                       :updated_at    (hsql/raw "now()")})

  {:code 0 :msg "success"})

(defn generate-token []
  (-> (hash/sha256 (.toString (java.util.UUID/randomUUID)))
      (codecs/bytes->hex)))


(defn forget-password [params]
  (let [{:keys [mobile]} params
        entity (first (db/select models/User :mobile mobile))]
    ;; check if user not exists
    (if (empty? entity)
      (throw (ex-info "check" {:type ::exception/check :msg "user does not exits!"})))

    ;; check sms
    (let [{:keys [mobile code]} params
          params {:phone mobile :code code}]
      (http-service/execute :post "http://localhost:3000/api/check" params))

    ;; update db
    (let [token (generate-token)]
      (db/update! models/User (:id entity) {:reset_password_token   token
                                            :reset_password_send_at (hsql/raw "now()")})))
  {:code 0 :msg "success"})

(defn reset-password [params]
  (let [send-time (time/minus (time/local-date-time) (time/minutes 10))
        entity (first (db/select models/User :reset_password_token (:token params)
                                             :reset_password_send_at [:> send-time]))]

    ;; check entity
    (if (empty? entity)
      (throw (ex-info "check" {:type ::exception/check :msg "token does not exits!"})))

    ;; check confirmation
    (if-not (= (:password params) (:password-confirmation params))
      (throw (ex-info "check" {:type ::exception/check :msg "confirmation not match!"})))

    ;; update db
    (db/update! models/User (:id entity) {:password      (hashers/derive (:password params))
                                          :updated_at    (hsql/raw "now()")}))

  {:code 0 :msg "success"})
